using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using System;
using System.Collections.Generic;

namespace IQIGame.Onigao.Game
{
    public class CacheUIHelper
    {
        // 显示队列数据
        private List<CacheUI> showList = new List<CacheUI>(16);
        private Func<Type, UIBaseWindow> _getWindow;
        private Func<Type, UIBaseData, UniTask> _recoverWindowAsync;

        public CacheUIHelper(Func<Type, UIBaseWindow> getWindow, Func<Type, UIBaseData, UniTask> recoverWindowAsync)
        {
            this._getWindow = getWindow;
            this._recoverWindowAsync = recoverWindowAsync;
        }

        public void InitShowStack(UIBaseWindow window)
        {
            List<CacheUI> operateList = ListPool<CacheUI>.Get();
            //收集window以下的UI，如果window是全屏UI的话
            this.GetFullScreenUIOperateList(window, operateList);
            //如果是全屏UI则关闭其他UI并记录在列表里
            this.CloseOrHideOperateList(operateList, window);
            //创建Cache
            CacheUI cacheUI = this.AddUI(window);
            //复制list
            cacheUI.RecordOperateList(operateList);
            //释放临时list
            ListPool<CacheUI>.Put(operateList);
        }

        private void GetFullScreenUIOperateList(UIBaseWindow window, List<CacheUI> needOperateList)
        {
            if (this.IsFullScreenUI(window))
            {
                for (var i = this.showList.Count - 1; i >= 0; i--)
                {
                    CacheUI cache = this.showList[i];
                    if (cache.activeWindow == null)
                    {
                        LogGame.LogError("缓存的显示UI列表里存在错误数据");
                        continue;
                    }
                    //如果缓存的UI在更上层，不处理，因为全屏UI只能关闭其下层UI
                    var cacheSetting = cache.activeWindow.winSetting;
                    var cacheLayer = (int)cacheSetting.layer;
                    var fullScreenWindowLayer = (int)window.winSetting.layer;
                    if (cacheLayer > fullScreenWindowLayer || (cacheLayer == fullScreenWindowLayer && cacheSetting.sortOrder > window.winSetting.sortOrder))
                    {
                        continue;
                    }
                    var windowLast = this._getWindow(cache.windowType);
                    //如果UI已关闭则直接移除缓存并销毁（？怀疑是否存在这种可能，因为没出bug暂时不改代码，by：Hongfeng）
                    if (windowLast == null)
                    {
                        this.Remove(cache, true);
                        continue;
                    }
                    //实体UI不应该受UI管，应该由场景管，否则容易出问题，因为实体UI和场景的代码可能是耦合的
                    //可以通过类似灵魂1开关全屏UI时派发事件来控制场景的显示
                    if (windowLast is UIEntityWindow)
                    {
                        continue;
                    }
                    //注意这里因为涉及Remove，遍历是倒着的，这导致needOperateList顺序与showList相反
                    //write by Gongyanghui，comment by Hongfeng

                    //注意：CacheUI内部涉及到CacheUI的嵌套引用（fullScreenOperateList），所以这里要使用clone的对象，否则引用关系太复杂容易出bug，
                    //leaveData和fullScreenOperateList都是在特定业务逻辑里设置的，showList里的CacheUI并没有这些数据
                    var newCache = CacheUI.GetFromPool();
                    newCache.Sync(cache.windowType, null);
                    newCache.RecordLeaveData(windowLast.GetLeaveData());
                    needOperateList.Add(newCache);
                }
            }
        }

        private bool IsFullScreenUI(UIBaseWindow window)
        {
            return window.winSetting.isFullScreen;
        }

        /// <summary>
        /// 移除并释放缓存
        /// </summary>
        /// <param name="cacheUI"></param>
        private void Remove(CacheUI cacheUI, bool needClearCache)
        {
            showList.Remove(cacheUI);
            if (needClearCache)
            {
                cacheUI.Put2Pool();
            }
        }

        private void CloseOrHideOperateList(List<CacheUI> needList, UIBaseWindow window)
        {
            for (int i = 0; i < needList.Count; i++)
            {
                CacheUI cache = needList[i];
                var windowLast = this._getWindow(cache.windowType);
                if (windowLast != window)
                {
                    this.CloseWindow(windowLast);
                }
            }
        }

        private void CloseWindow(UIBaseWindow window)
        {
            ManagerCenter.UI.CloseWindow(window, false);
        }

        private CacheUI AddUI(UIBaseWindow window)
        {
            CacheUI cache = CacheUI.GetFromPool();
            cache.Sync(window.GetType(), window);
            this.showList.Add(cache);
            return cache;
        }

        /// <summary>
        /// 全屏UI关闭时还原UI
        /// </summary>
        /// <param name="closingWindow">关闭的UI</param>
        /// <returns></returns>
        public async UniTaskVoid OnCloseUI(UIBaseWindow closingWindow, bool isRecover)
        {
            var closingWindowCache = this.GetTopCacheUI(closingWindow.GetType());
            if (closingWindowCache == null)
                return;
            //先从列表里移除，避免后续判断（如GetTopCacheUI）出错
            //不清空，方法最后再清空
            this.Remove(closingWindowCache, false);
            if (isRecover)
            {
                //获取全屏UI关闭的UI缓存列表，不是全屏UI列表为空
                var list = closingWindowCache.fullScreenOperateList;
                //cache.fullScreenOperateList顺序和this.showList相反，第一个是Top，详情参考方法：this.GetFullScreenUIOperateList()
                //且cache.fullScreenOperateList都是已关闭的UI，不在this.showList里

                //另外，fullScreenOperateList只会存储closingWindowCache.windowType关闭的UI，如果它内部也有全屏UI，那么这个全屏UI一定是最后一个元素
                for (int i = 0; i < list.Count; i++)
                {
                    CacheUI cache = list[i];
                    if (cache.CheckNeedRecover())
                    {
                        //还原UI
                        await _recoverWindowAsync(cache.windowType, cache.leaveData);
                        //还原以后当前的TopUICache是通过RecoverWindowAsync内部逻辑新建的，且新建时，CacheUI.Sync()没有设置fullScreenOperateList
                        //所以这里需要把cache里的fullScreenOperateList取出来填充进去，并清释放cache
                        CacheUI topCacheUI = this.GetTopCacheUI(cache.windowType);
                        topCacheUI.RecordOperateList(cache.fullScreenOperateList);
                        //先release cache，后续closingWindowCache.Put2Pool会清除cache的引用
                        cache.Put2Pool();
                    }
                }
            }
            //释放自身的缓存
            closingWindowCache.Put2Pool();
        }

        private CacheUI GetTopCacheUI(Type type)
        {
            for (var i = this.showList.Count - 1; i > -1; i--)
            {
                CacheUI cache = this.showList[i];
                if (type == cache.windowType)
                    return cache;
            }
            return default;
        }

        public void Clear()
        {
            for (var i = showList.Count - 1; i > -1; i--)
            {
                showList[i].Put2Pool();
            }
            this.showList.Clear();
        }
    }
}
